package com.bungarus.busi;

import com.bungarus.model.Device;
import io.lettuce.core.RedisFuture;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

@Component
public class DeviceService {
    public static Device.Status check(Device device) {
        DeviceStorage storage = DeviceStorage.getInstance();
        Device storedDevice = storage.retrieveEntity(storage.makeKey(device), device.getId());
        if(null == storedDevice) {
            return Device.Status.NEW;
        }
        else {
            return storedDevice.getStatus();
        }
    }

    private static final class DeviceStorage extends RedisStorage<String, Device> {
        private static DeviceStorage storage = new DeviceStorage();
        private DeviceStorage() {
            super();
        }

        public static DeviceStorage getInstance() {
            return storage;
        }

        @Override
        public String storageUrl() {
            return AccessBusiProcessing.springContext.getBean("tokenRedisUrl", String.class);
        }

        @Override
        public Integer storageDbNumber() {
            return AccessBusiProcessing.springContext.getBean("tokenRedisDb", Integer.class);
        }

        @Override
        public Integer storageConnectionTimeout() {
            return AccessBusiProcessing.springContext.getBean("tokenRedisTimeout", Integer.class);
        }

        @Override
        public String makeKey(Device entity) {
            StringBuilder sb = new StringBuilder("user:");
            sb.append(entity.getTenantId());
            sb.append(":");
            sb.append(entity.getMid());
            return sb.toString();
        }

        @Override
        public void storeEntity(String key, String field, Device entity) {
            Map<String, String> map = new HashMap<>();
            map.put(field, entity.getStatus().name());
            map.put("created", String.valueOf(System.currentTimeMillis()));

            connection.async().hmset(key, map);
            //TODO: call remote device service to persist the device into SQL DB
        }

        @Override
        public Device retrieveEntity(String key, String field) {
            RedisFuture<String> result = connection.async().hget(key, field);

            String str[] = key.split(":");
            Device.Builder builder = Device.Builder.newBuilder();
            builder.tenant(str[1]).user(str[2]).id(field);
            try {
                String r = result.get(3, TimeUnit.SECONDS);
                //if the device doesn't be found, it's a new device and save it
                Device.Status status = (null == r || r.length() <= 0)? Device.Status.NEW : Device.Status.valueOf(r);
                Device device = builder.status(status).build();
                if(null == r || r.length() <= 0) {
                    storeEntity(key, field, device);
                }
                return device;
            }
            catch (InterruptedException | ExecutionException | TimeoutException e) {
                e.printStackTrace();
            }
            return builder.status(Device.Status.INVALID).build();
        }
    }
}
